package com.alcatel_lucent.osp.action;

import com.alcatel_lucent.osp.interceptors.AuthorizationInterceptor;
import com.alcatel_lucent.osp.model.User;
import com.alcatel_lucent.osp.service.AuthenticationService;
import com.alcatel_lucent.osp.service.DaoService;
import com.opensymphony.xwork2.ActionContext;
import net.sf.json.JSONObject;
import org.apache.struts2.StrutsStatics;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import org.apache.struts2.interceptor.SessionAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.DigestUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.net.URLEncoder;
import java.util.*;

import static com.alcatel_lucent.osp.interceptors.AuthorizationInterceptor.COOKIE_REMEMBER_KEY;
import static com.alcatel_lucent.osp.interceptors.AuthorizationInterceptor.COOKIE_REMEMBER_KEY_SEPARATOR;

@SuppressWarnings("serial")
public class LoginAction extends BaseAction implements SessionAware, ServletResponseAware, ServletRequestAware {

    @Autowired
    private AuthenticationService authenticationService;
    private Map<String, Object> session;
    private HttpServletResponse response;
    private HttpServletRequest request;

    private String csl;
    private String password;
    private String rememberMe;

    private Integer timeZoneOffset;

    public static final String OSP_SALT = "osp_login_key";

    public static final int TWO_WEEKS = 60 * 60 * 24 * 14;
    @Value("${httpPort}")
    private String httpPort;

    @Autowired
    private DaoService daoService;

    private Collection<String> testCSL = Arrays.asList("test", "notOwner");

    @Action(value = "logout", results = {
            @Result(name = SUCCESS, type = "redirect", location = "${indexPage}")
    })
    public String logout() {
        User user = UserContext.getInstance().getUser();
        HttpSession httpSession = request.getSession();
        log.info("User {} logout, session id={}", user.getCil(), httpSession.getId());
        UserContext.removeUserContext();
        httpSession.removeAttribute(UserContext.SESSION_USER_CONTEXT);
        httpSession.invalidate();
        response.addCookie(getCookie(COOKIE_REMEMBER_KEY, "anonymous", 0));
        return SUCCESS;
    }

    public String getIndexPage() {
        String lastAccessedURL = (String) session.get(AuthorizationInterceptor.LAST_ACCESSED_URL_KEY);
        if (lastAccessedURL == null) {
            lastAccessedURL = "/index";
        }
        return "http://" + request.getServerName() + ":" + httpPort + request.getContextPath() + lastAccessedURL;
    }

    @Action(results = {
            @Result(name = SUCCESS, type = "redirect", location = "${indexPage}"),
            @Result(name = INPUT, type = "dispatcher", location = "/login.jsp")
    })
    @Override
    public String execute() throws Exception {
        log.info("csl ={}, password={}, remember me={}, timeZoneOffset={}, session.id ={}", new Object[]{csl, "********", rememberMe, timeZoneOffset, request.getSession().getId()});

        //user can not remember
//        for test user
        User user = testCSL.contains(csl) ?
                (User) daoService.retrieveOne("from User where csl=:csl", JSONObject.fromObject(String.format("{'csl': '%s'}", csl)), new String[]{"categories"}) :
                authenticationService.login(csl, password);
        if (null == user) {
            this.addActionError("csl or password incorrect!");
            return INPUT;
        }

//        User user = authenticationService.login(csl, password);
        TimeZone clientTimeZone = null != timeZoneOffset ? new SimpleTimeZone(timeZoneOffset, user.getCsl() + "_TimeZone") : null;
        UserContext userContext = new UserContext(getLocale(), user, clientTimeZone);
        UserContext.setUserContext(userContext);
        session.put(UserContext.SESSION_USER_CONTEXT, userContext);

        if (null != rememberMe && "on".equals(rememberMe)) {//save user info into Cookies
            // generate digest for user
            String digest = DigestUtils.md5DigestAsHex((csl + OSP_SALT).getBytes("utf-8"));
            String value = URLEncoder.encode(
                    String.format("%s%s%s%s%s", csl, COOKIE_REMEMBER_KEY_SEPARATOR, digest, COOKIE_REMEMBER_KEY_SEPARATOR, null == timeZoneOffset ? "" : timeZoneOffset),
                    "UTF-8"
            );
            response.addCookie(getCookie(COOKIE_REMEMBER_KEY, value, TWO_WEEKS));
        } else {
            //remove rememberMe cookie
            response.addCookie(getCookie(COOKIE_REMEMBER_KEY, "anonymous", 0));
        }

        return SUCCESS;
    }


    public Integer getTimeZoneOffset() {
        return timeZoneOffset;
    }

    public void setTimeZoneOffset(Integer timeZoneOffset) {
        this.timeZoneOffset = timeZoneOffset;
    }

    public AuthenticationService getAuthenticationService() {
        return authenticationService;
    }

    public void setAuthenticationService(AuthenticationService authenticationService) {
        this.authenticationService = authenticationService;
    }

    public String getCsl() {
        return csl;
    }

    public void setCsl(String csl) {
        this.csl = csl;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRememberMe() {
        return rememberMe;
    }

    public void setRememberMe(String rememberMe) {
        this.rememberMe = rememberMe;
    }

    @Override
    public void setSession(Map<String, Object> session) {
        this.session = session;
    }

    @Override
    public void setServletResponse(HttpServletResponse response) {
        this.response = response;
    }

    @Override
    public void setServletRequest(HttpServletRequest request) {
        this.request = request;
    }

    /**
     * Generate a cookie
     *
     * @param name   the cookie name
     * @param value  the cookie value
     * @param maxAge the maxAge of the cookie, 0 indicate the cookie will be deleted
     */
    public static Cookie getCookie(String name, String value, int maxAge, String path) {
        Cookie cookie = new Cookie(name, value);
        cookie.setMaxAge(maxAge);
        cookie.setPath(path);
        return cookie;
    }

    /**
     * Generate a server root cookie
     */
    public static Cookie getCookie(String name, String value, int maxAge) {
        HttpServletRequest request = (HttpServletRequest) ActionContext.getContext().get(StrutsStatics.HTTP_REQUEST);
        return getCookie(name, value, maxAge, request.getContextPath());
    }

}
